const { mkdirSync, delDir, writeFileSync } = require("./FileHelper");
const { getMergeConfig } = require("./mergeConfig");
const { refMap, nameToCaml, findRef } = require("./utils");

const baseRefNames = [
  "Result«boolean»",
  "Result«string»",
  "Result«object»"
]

module.exports.baseRefNames = baseRefNames

function shouldGenDefFile(_className) {
  if(baseRefNames.includes(_className)) {
    return false;
  }
  return true;
}

function Definition(_className, data) {
  this.data = data;
  /// 判断是否需要生成定义文件 例如 Result<String> 是不需要生成文件的
  this.hasRef = shouldGenDefFile(_className)
  data.className = _className;
  data.refs = [];
  data.refName = `#/definitions/${_className}`;
  /// 基础类型需要引入Result引用
  if(baseRefNames[_className]) {
    data.refs.push('#/definitions/Result')
  }
  data.findRef = function(ref) {
    var _ref = findRef(ref)
    if(!_ref) return null
    if(!_ref.hasRef) return null
    return !!_ref ? _ref.data : null
  }

  Object.keys(data.properties || {}).forEach((propertyName) => {
    var property = data.properties[propertyName];
    if(property["$ref"]) {
      data.refs.push(property["$ref"])
    }
    if(property.type === "array" && property.items.$ref) {
      data.refs.push(property.items.$ref)
    }
  })
  data.refs = Array.from(new Set(data.refs))
}

module.exports.Definition = Definition;



function genDefinitions() {
  var mergeConfig = getMergeConfig()
  var definitions = [];
  var refs = [];

  Object.keys(mergeConfig.apiDoc.definitions).forEach((_className)=> {
    var definition = new Definition(_className, mergeConfig.apiDoc.definitions[_className])
    if(definition.data.refName) refMap[definition.data.refName] = definition;
    refs = refs.concat(definition.data.refs)
    definitions.push(definition);
  })

  mkdirSync(mergeConfig.DIR_CONTROLLERS)
  delDir(mergeConfig.DIR_DEFINITIONS)
  mkdirSync(mergeConfig.DIR_DEFINITIONS)

  writeFileSync(`${mergeConfig.DIR_DEFINITIONS}/Definition.${mergeConfig.DEFINITION_FILE_EXT}`, mergeConfig.DEFINITION_INTERFACE_DEFINE);
  writeFileSync(`${mergeConfig.DIR_DEFINITIONS}/Result.${mergeConfig.DEFINITION_FILE_EXT}`, mergeConfig.RESULT_INTEFACE_DEFINE);

  definitions.forEach(item=> {
    if(!item.hasRef) return;
    var definition = item.data;
    var className = nameToCaml(definition.className);
    var defineFilePath = `${mergeConfig.DIR_DEFINITIONS}/${className}.${mergeConfig.DEFINITION_FILE_EXT}`;

    if(definition.className.includes("Result")) {
      if(definition.className != "Result" && definition.className.includes("Result«")) {
        var def = definition.findRef(definition.refs[0]);
        if(!def) {
          console.warn("def error =======================>", definition.refs[0]);
          return;
        }
        var refClassName = nameToCaml(definition.findRef(definition.refs[0]).className);
        var extendsClassName = definition.className.replace(/«/gi, "<").replace(/»/gi, ">");
        var content = mergeConfig.resultClassTmpl(className, extendsClassName, refClassName)
        writeFileSync(defineFilePath, content)
      } else if(definition.className.indexOf('Result') !== 0) {
        var content = mergeConfig.definitionClassTmpl(
          className,
          mergeConfig.definitionClassRefsTmpl(definition.refs.map(ref=> nameToCaml(definition.findRef(ref).className))),
          mergeConfig.definitionPropertiesTmpl(definition)
        )
        writeFileSync(defineFilePath, content)
      }
    } else {
      var content = mergeConfig.definitionClassTmpl(
        className,
        mergeConfig.definitionClassRefsTmpl(definition.refs.map(ref=> nameToCaml(definition.findRef(ref).className))),
        mergeConfig.definitionPropertiesTmpl(definition)
      )
      writeFileSync(defineFilePath, content)
    }
  })
}

module.exports.genDefinitions = genDefinitions
